<template>
  <view class="hypothetical-container">
    <!-- Header -->
    <view class="header">
      <text class="title">🌧️ 假拟降雨场景生成</text>
      <text class="subtitle">基于真实预报生成多个假拟降雨场景进行对比分析</text>
    </view>

    <!-- Configuration Panel -->
    <view class="config-panel" v-if="!loading && !results">
      <view class="config-section">
        <view class="section-title">
          <text class="icon">⚙️</text>
          <text>生成配置</text>
        </view>
        
        <!-- Method Selection -->
        <view class="form-group">
          <text class="label">分配方式</text>
          <view class="radio-group">
            <view 
              class="radio-item" 
              :class="{ active: config.method === 'average' }"
              @click="config.method = 'average'"
            >
              <view class="radio-icon">{{ config.method === 'average' ? '●' : '○' }}</view>
              <view class="radio-content">
                <text class="radio-label">平均分配</text>
                <text class="radio-desc">将总雨量均匀分配到各时段</text>
              </view>
            </view>
            <view 
              class="radio-item" 
              :class="{ active: config.method === 'proportional' }"
              @click="config.method = 'proportional'"
            >
              <view class="radio-icon">{{ config.method === 'proportional' ? '●' : '○' }}</view>
              <view class="radio-content">
                <text class="radio-label">等比例放大</text>
                <text class="radio-desc">按原降雨比例放大至目标总量</text>
              </view>
            </view>
          </view>
        </view>

        <!-- Rainfall Values Input -->
        <view class="form-group">
          <text class="label">总降雨量 (mm)</text>
          <view class="rainfall-input-container">
            <view 
              v-for="(value, index) in config.rainfallValues" 
              :key="index"
              class="rainfall-value-item"
            >
              <input 
                type="digit"
                v-model="config.rainfallValues[index]"
                class="rainfall-input"
                placeholder="输入降雨量"
              />
              <view class="remove-btn" @click="removeRainfallValue(index)" v-if="config.rainfallValues.length > 1">
                <text>×</text>
              </view>
            </view>
            <view class="add-btn" @click="addRainfallValue">
              <text>+ 添加场景</text>
            </view>
          </view>
        </view>

        <!-- Quick Presets -->
        <view class="form-group">
          <text class="label">快速预设</text>
          <view class="preset-buttons">
            <view class="preset-btn" @click="applyPreset('light')">
              <text>🌦️ 小雨场景</text>
            </view>
            <view class="preset-btn" @click="applyPreset('moderate')">
              <text>🌧️ 中雨场景</text>
            </view>
            <view class="preset-btn" @click="applyPreset('heavy')">
              <text>⛈️ 大雨场景</text>
            </view>
          </view>
        </view>
      </view>

      <!-- Action Buttons -->
      <view class="action-buttons">
        <view class="btn btn-secondary" @click="closeModal">
          <text>取消</text>
        </view>
        <view 
          class="btn btn-primary" 
          :class="{ disabled: !canSubmit }"
          @click="submitHypothetical"
        >
          <text>{{ isProcessing ? '处理中...' : '生成并执行预报' }}</text>
        </view>
      </view>
    </view>

    <!-- Loading State -->
    <view class="loading-container" v-if="loading">
      <view class="loading-card">
        <view class="spinner"></view>
        <text class="loading-text">{{ loadingMessage }}</text>
        <view class="progress-steps">
          <view 
            v-for="(step, index) in progressSteps" 
            :key="index"
            class="progress-step"
            :class="{ active: step.active, completed: step.completed }"
          >
            <view class="step-icon">{{ step.completed ? '✓' : (step.active ? '⟳' : '○') }}</view>
            <text class="step-text">{{ step.text }}</text>
          </view>
        </view>
      </view>
    </view>

    <!-- Results Display -->
    <view class="results-container" v-if="results && !loading">
      <view class="results-header">
        <text class="results-title">🎯 假拟场景对比分析</text>
        <view class="btn btn-secondary btn-sm" @click="resetForm">
          <text>重新生成</text>
        </view>
      </view>

      <!-- AI Analysis Card -->
      <view class="ai-analysis-card" v-if="showAIAnalysis">
        <view class="ai-header">
          <view class="ai-title-row">
            <text class="ai-icon">🤖</text>
            <text class="ai-title">AI 智能分析</text>
            <view class="ai-status-badge" :class="aiStatus">
              <text class="status-dot"></text>
              <text class="status-text">{{ getAIStatusText() }}</text>
            </view>
          </view>
          <view class="ai-actions" v-if="aiStatus === 'error' || aiStatus === 'disconnected'">
            <view class="retry-btn" @click="retryAIConnection">
              <text>🔄 重试</text>
            </view>
          </view>
        </view>

        <!-- AI Analysis Content -->
        <view class="ai-content">
          <!-- Connecting State -->
          <view class="ai-connecting" v-if="aiStatus === 'connecting'">
            <view class="connecting-spinner"></view>
            <text class="connecting-text">正在连接 AI 分析服务...</text>
          </view>

          <!-- Connected/Analyzing State -->
          <view class="ai-analyzing" v-else-if="aiStatus === 'connected' && !aiAnalysisText">
            <view class="analyzing-animation">
              <text class="dot">●</text>
              <text class="dot">●</text>
              <text class="dot">●</text>
            </view>
            <text class="analyzing-text">AI 正在分析假拟场景...</text>
          </view>

          <!-- Analysis Text Display -->
          <view class="ai-text-display" v-if="aiAnalysisText">
            <!-- Question Title -->
            <view class="ai-question-title" v-if="aiQuestion">
              <text class="question-icon">💡</text>
              <text class="question-text">{{ aiQuestion }}</text>
            </view>
            
            <!-- Answer Content -->
            <view class="ai-answer-content">
              <text class="ai-text">{{ displayedText }}</text>
              <view class="typing-cursor" v-if="isTyping"></view>
            </view>
          </view>

          <!-- Error State -->
          <view class="ai-error" v-if="aiStatus === 'error'">
            <text class="error-icon">⚠️</text>
            <text class="error-text">{{ aiErrorMessage }}</text>
            <view class="error-troubleshooting">
              <text class="troubleshooting-title">💡 故障排查建议:</text>
              <view class="troubleshooting-steps">
                <text class="step">• 检查 AI 分析服务是否正常运行</text>
                <text class="step">• 检查网络连接状态</text>
                <text class="step">• 联系管理员确认服务器状态</text>
                <text class="step">• 稍后可点击"重试"按钮再次尝试</text>
              </view>
            </view>
          </view>

          <!-- Disconnected State -->
          <view class="ai-disconnected" v-if="aiStatus === 'disconnected'">
            <text class="disconnected-icon">🔌</text>
            <text class="disconnected-text">连接已断开</text>
          </view>
        </view>
      </view>

      <!-- Real Forecast -->
      <view class="forecast-card real-forecast">
        <view class="card-header">
          <text class="card-title">📊 真实预报（基准场景）</text>
          <view class="rainfall-badge real">
            <text>总雨量: {{ results.real_data?.rainfall ? calculateTotalRainfall(results.real_data.rainfall) : 0 }} mm</text>
          </view>
        </view>
        <view class="card-content">
          <view class="chart-section" v-if="results.real_data?.forecast_result?.timeSeries">
            <ForecastChart 
              :time-series="results.real_data.forecast_result.timeSeries"
              :chart-id="'real-forecast-chart'"
            />
          </view>
          <view class="no-chart-message" v-else>
            <text>📊 图表数据加载中...</text>
          </view>
        </view>
      </view>

      <!-- Hypothetical Forecasts -->
      <view class="hypothetical-grid">
        <view 
          v-for="(item, index) in results.hypothetical_data" 
          :key="item.session_id"
          class="forecast-card hypothetical-forecast"
        >
          <view class="card-header">
            <text class="card-title">🌧️ 假拟场景 {{ index + 1 }}</text>
            <view class="rainfall-badge hypothetical">
              <text>总雨量: {{ item.rainfall ? calculateTotalRainfall(item.rainfall) : 0 }} mm</text>
            </view>
          </view>
          <view class="method-tag">
            <text>{{ getMethodLabel(item.hypothetical_method) }}</text>
          </view>
          <view class="card-content">
            <!-- Chart Section -->
            <view class="chart-section" v-if="item.forecast_result?.timeSeries && item.forecast_result.timeSeries.length > 0">
              <ForecastChart 
                :time-series="item.forecast_result.timeSeries"
                :chart-id="'hypo-forecast-chart-' + index"
              />
            </view>
            <view class="no-chart-message" v-else>
              <text class="icon">📊</text>
              <text class="message-text">假拟场景预报已完成</text>
              <text class="message-detail">图表数据暂未加载，请联系管理员配置</text>
              <text class="session-info">Session ID: {{ item.session_id }}</text>
            </view>
            
            <!-- Additional Info -->
            <view class="info-grid">
              <view class="info-item">
                <text class="info-label">站点</text>
                <text class="info-value">{{ item.stcd_name }}</text>
              </view>
              <view class="info-item">
                <text class="info-label">模型</text>
                <text class="info-value">{{ item.model_type }}</text>
              </view>
              <view class="info-item">
                <text class="info-label">方案</text>
                <text class="info-value">{{ item.scheme_name || item.plcd }}</text>
              </view>
              <view class="info-item">
                <text class="info-label">预报时长</text>
                <text class="info-value">{{ item.clen }} 天</text>
              </view>
            </view>
          </view>
        </view>
      </view>
    </view>
  </view>
</template>

<script>
import { ref, computed, watch, onUnmounted } from 'vue'
import { forecastApi } from '../api/api'
import ForecastChart from '../charts/ForecastChart.vue'
import { connectLLMAnalysis, closeLLMConnection } from '../utils/llmWebSocket'

export default {
  name: 'HypotheticalRainfall',
  components: {
    ForecastChart
  },
  props: {
    sessionId: {
      type: String,
      required: false,
      default: null
    },
    llmConfig: {
      type: Object,
      default: null
    }
  },
  emits: ['close'],
  setup(props, { emit }) {
    // 🔍 调试：打印接收到的 sessionId
    console.log('🌦️ HypotheticalRainfall 组件初始化')
    console.log('   sessionId:', props.sessionId)
    console.log('   llmConfig:', props.llmConfig)
    
    // 初始化配置，如果有 LLM 配置则使用，否则使用默认值
    const config = ref({
      method: props.llmConfig?.method || 'proportional',
      rainfallValues: props.llmConfig?.values?.map(v => v.toString()) || ['80', '100', '120']
    })
    
    // 如果是 LLM 触发的，打印提示
    if (props.llmConfig) {
      console.log('✅ [LLM配置] 假拟降雨已自动填充:')
      console.log('   方法:', config.value.method)
      console.log('   降雨量:', config.value.rainfallValues)
    }
    
    // 监听 llmConfig 变化（处理异步传递）
    watch(() => props.llmConfig, (newConfig, oldConfig) => {
      console.log('🔄 [HypotheticalRainfall] watch 触发')
      console.log('   oldConfig:', oldConfig)
      console.log('   newConfig:', newConfig)
      console.log('   newConfig JSON:', JSON.stringify(newConfig))
      
      if (newConfig && newConfig.method && newConfig.values && Array.isArray(newConfig.values)) {
        console.log('🔄 [LLM配置] 检测到有效配置:')
        console.log('   method:', newConfig.method)
        console.log('   values:', newConfig.values)
        console.log('   values长度:', newConfig.values.length)
        
        // 完全替换配置对象以确保响应式更新
        const newRainfallValues = newConfig.values.map(v => {
          const str = v.toString()
          console.log(`   转换: ${v} (${typeof v}) -> "${str}"`)
          return str
        })
        
        config.value = {
          method: newConfig.method,
          rainfallValues: newRainfallValues
        }
        
        console.log('✅ [LLM配置] 配置已更新:')
        console.log('   方法:', config.value.method)
        console.log('   降雨量:', config.value.rainfallValues)
        console.log('   降雨量 JSON:', JSON.stringify(config.value.rainfallValues))
      } else {
        console.log('❌ [LLM配置] 配置无效或不完整')
        if (!newConfig) console.log('   newConfig 为空')
        else if (!newConfig.method) console.log('   缺少 method')
        else if (!newConfig.values) console.log('   缺少 values')
        else if (!Array.isArray(newConfig.values)) console.log('   values 不是数组')
      }
    }, { immediate: true, deep: true })

    const loading = ref(false)
    const loadingMessage = ref('')
    const isProcessing = ref(false)
    const results = ref(null)

    // AI 分析相关状态
    const showAIAnalysis = ref(false)
    const aiStatus = ref('idle') // 'idle', 'connecting', 'connected', 'error', 'disconnected'
    const aiAnalysisText = ref('')
    const aiQuestion = ref('') // 分析的问题
    const displayedText = ref('')
    const isTyping = ref(false)
    const aiErrorMessage = ref('')
    const aiWebSocket = ref(null)
    const originalSessionId = ref(null) // 保存 original_session_id
    let typingInterval = null // 打字机定时器

    const progressSteps = ref([
      { text: '生成假拟场景', active: false, completed: false },
      { text: '提交预报任务', active: false, completed: false },
      { text: '等待计算完成', active: false, completed: false },
      { text: '获取结果数据', active: false, completed: false }
    ])

    const canSubmit = computed(() => {
      return config.value.rainfallValues.length > 0 && 
             config.value.rainfallValues.every(v => v && parseFloat(v) > 0) &&
             !isProcessing.value
    })

    const addRainfallValue = () => {
      config.value.rainfallValues.push('')
    }

    const removeRainfallValue = (index) => {
      config.value.rainfallValues.splice(index, 1)
    }

    const applyPreset = (type) => {
      switch (type) {
        case 'light':
          config.value.rainfallValues = ['50', '70', '90']
          break
        case 'moderate':
          config.value.rainfallValues = ['100', '120', '140', '160']
          break
        case 'heavy':
          config.value.rainfallValues = ['180', '200', '220', '250']
          break
      }
    }

    const updateProgressStep = (stepIndex, active, completed) => {
      progressSteps.value[stepIndex].active = active
      progressSteps.value[stepIndex].completed = completed
    }

    const submitHypothetical = async () => {
      if (!canSubmit.value) {
        console.warn('⚠️ submitHypothetical 被调用但 canSubmit 为 false')
        return
      }

      // 检查 sessionId 是否有效
      if (!props.sessionId || props.sessionId === '' || props.sessionId === 'null') {
        console.error('❌ sessionId 无效:', props.sessionId)
        uni.showToast({
          title: '请先执行一次预报，生成有效的会话后才能创建假拟场景',
          icon: 'none',
          duration: 3000
        })
        return
      }

      console.log('🌦️ ========== 开始假拟降雨流程 ==========')
      console.log('🌦️ sessionId:', props.sessionId)
      console.log('🌦️ 降雨量配置:', config.value.rainfallValues)
      console.log('🌦️ 分配方式:', config.value.method)

      isProcessing.value = true
      loading.value = true
      loadingMessage.value = '正在生成假拟降雨场景...'

      try {
        // Step 1: 批量生成假拟场景
        console.log('🌦️ [步骤1] 开始批量生成假拟场景...')
        updateProgressStep(0, true, false)
        const totalRainfalls = config.value.rainfallValues.map(v => parseFloat(v))
        console.log('🌦️ [步骤1] 转换后的降雨量数组:', totalRainfalls)
        
        const batchResult = await forecastApi.batchHypotheticalRainfall(
          props.sessionId,
          totalRainfalls,
          config.value.method
        )
        updateProgressStep(0, false, true)
        console.log('✅ [步骤1] 假拟场景生成成功:', batchResult)
        
        // 保存 original_session_id 用于后续 AI 分析
        if (batchResult.original_session_id) {
          originalSessionId.value = batchResult.original_session_id
          console.log('💾 [步骤1] 保存 original_session_id:', originalSessionId.value)
        }

        // Step 2: 提交所有预报任务（原始 + 假拟）
        console.log('🚀 [步骤2] 开始提交所有预报任务...')
        updateProgressStep(1, true, false)
        loadingMessage.value = '正在提交预报任务...'
        
        const allSessionIds = [
          props.sessionId,
          ...batchResult.generated_sessions.map(s => s.session_id)
        ]
        console.log('🚀 [步骤2] 所有 sessionId:', allSessionIds)

        const submitPromises = allSessionIds.map((sessionId, index) => {
          console.log(`🚀 [步骤2] 提交任务 ${index + 1}/${allSessionIds.length}, sessionId: ${sessionId}`)
          return forecastApi.submitCalculateBySession(sessionId, false)
        })
        await Promise.all(submitPromises)
        updateProgressStep(1, false, true)
        console.log('✅ [步骤2] 所有预报任务已提交')

        // Step 3: 等待计算完成（轮询）
        console.log('⏳ [步骤3] 等待计算完成...')
        updateProgressStep(2, true, false)
        loadingMessage.value = '正在计算预报结果，请稍候...'
        await waitForCalculations(allSessionIds)
        updateProgressStep(2, false, true)
        console.log('✅ [步骤3] 计算完成')

        // Step 4: 获取结果
        console.log('📊 [步骤4] 开始获取预报结果...')
        updateProgressStep(3, true, false)
        loadingMessage.value = '正在获取预报结果...'
        const hypotheticalInfo = await forecastApi.getHypotheticalInfo(props.sessionId)
        updateProgressStep(3, false, true)
        
        results.value = hypotheticalInfo
        console.log('✅ [步骤4] 假拟降雨结果:', results.value)
        console.log('📊 real_data.forecast_result.timeSeries:', results.value?.real_data?.forecast_result?.timeSeries?.length)
        console.log('📊 hypothetical_data数量:', results.value?.hypothetical_data?.length)
        
        // 检查假拟场景是否有 timeSeries 数据
        if (results.value?.hypothetical_data) {
          console.log('🔍 [步骤4] 检查假拟场景数据结构...')
          let missingCount = 0
          
          results.value.hypothetical_data.forEach((item, idx) => {
            const hasTimeSeries = item?.forecast_result?.timeSeries && item.forecast_result.timeSeries.length > 0
            console.log(`📊 假拟场景${idx + 1}:`)
            console.log(`   session_id: ${item?.session_id}`)
            console.log(`   total_rainfall: ${item?.rainfall ? calculateTotalRainfall(item.rainfall) : 'N/A'} mm`)
            console.log(`   forecast_result: ${item?.forecast_result ? 'exists' : '❌ null'}`)
            console.log(`   timeSeries: ${hasTimeSeries ? '✅ ' + item.forecast_result.timeSeries.length + ' points' : '❌ MISSING'}`)
            
            if (!hasTimeSeries) {
              missingCount++
            }
          })
          
          if (missingCount > 0) {
            console.warn(`⚠️⚠️⚠️ ${missingCount}/${results.value.hypothetical_data.length} 个假拟场景缺少 forecast_result.timeSeries 数据`)
            console.warn('⚠️ 等待后端修复 get_hypothetical_info 接口，需要返回完整的 forecast_result.timeSeries')
          } else {
            console.log(`✅✅✅ 所有 ${results.value.hypothetical_data.length} 个假拟场景数据完整！`)
          }
        }
        console.log('🌦️ ========== 假拟降雨流程完成 ==========')

        // Step 5: 建立 AI 分析连接
        if (originalSessionId.value) {
          console.log('🤖 [步骤5] 开始 AI 智能分析...')
          connectToAIAnalysis(originalSessionId.value)
        }

        uni.showToast({
          title: '假拟预报生成成功',
          icon: 'success'
        })
      } catch (error) {
        console.error('❌ ========== 假拟降雨处理失败 ==========')
        console.error('❌ 错误详情:', error)
        console.error('❌ 错误消息:', error.message)
        console.error('❌ 错误堆栈:', error.stack)
        uni.showToast({
          title: '处理失败: ' + error.message,
          icon: 'none',
          duration: 3000
        })
      } finally {
        loading.value = false
        isProcessing.value = false
      }
    }

    const waitForCalculations = async (sessionIds) => {
      // 轮询等待所有计算完成
      const maxAttempts = 60 // 最多等待60次
      const pollInterval = 3000 // 每3秒轮询一次
      
      for (let attempt = 0; attempt < maxAttempts; attempt++) {
        console.log(`⏳ [轮询 ${attempt + 1}/${maxAttempts}] 检查计算状态...`)
        
        try {
          // 检查假拟信息，看是否所有场景都有 forecast_result
          const hypotheticalInfo = await forecastApi.getHypotheticalInfo(sessionIds[0])
          
          if (!hypotheticalInfo || !hypotheticalInfo.hypothetical_data) {
            console.log('   ⚠️ 假拟数据还未就绪')
            await new Promise(resolve => setTimeout(resolve, pollInterval))
            continue
          }
          
          // 检查所有假拟场景是否都有 forecast_result
          const allCompleted = hypotheticalInfo.hypothetical_data.every(item => {
            const hasResult = item.forecast_result !== null && item.forecast_result !== undefined
            console.log(`   场景 ${item.session_id}: ${hasResult ? '✅ 完成' : '⏳ 计算中'}`)
            return hasResult
          })
          
          // 同时检查 real_data 是否有 forecast_result
          const realCompleted = hypotheticalInfo.real_data?.forecast_result !== null
          console.log(`   真实预报: ${realCompleted ? '✅ 完成' : '⏳ 计算中'}`)
          
          if (allCompleted && realCompleted) {
            console.log('✅ 所有场景计算完成！')
            return
          }
          
          console.log(`   ⏳ 还有场景未完成，${pollInterval / 1000}秒后重试...`)
        } catch (error) {
          console.warn(`   ⚠️ 轮询出错: ${error.message}`)
        }
        
        await new Promise(resolve => setTimeout(resolve, pollInterval))
      }
      
      console.warn('⚠️ 达到最大轮询次数，停止等待')
      throw new Error('计算超时，请稍后手动刷新查看结果')
    }

    // ========== AI 分析相关函数 ==========
    
    // 连接 AI 分析服务
    const connectToAIAnalysis = (sessionId) => {
      console.log('🤖 [AI分析] 开始连接 WebSocket...')
      console.log('   Session ID:', sessionId)
      
      showAIAnalysis.value = true
      aiStatus.value = 'connecting'
      aiAnalysisText.value = ''
      displayedText.value = ''
      aiErrorMessage.value = ''
      
      try {
        aiWebSocket.value = connectLLMAnalysis(sessionId, {
          onOpen: () => {
            console.log('✅ [AI分析] 连接已建立')
            aiStatus.value = 'connected'
          },
          
          onMessage: (data, isText) => {
            console.log('📥 [AI分析] 收到消息:', data)
            
            if (isText) {
              // 纯文本消息：直接追加
              aiAnalysisText.value += data
              startTypingEffect()
            } else {
              // JSON 消息：根据 type 字段处理
              switch (data.type) {
                case 'welcome':
                  console.log('👋 [AI分析] 欢迎消息:', data.message)
                  // 欢迎消息不显示，只记录日志
                  break
                
                case 'processing':
                  console.log('⏳ [AI分析] 处理中:', data.message)
                  // 更新状态提示（可选）
                  break
                
                case 'answer':
                  console.log('💬 [AI分析] 收到分析结果')
                  // 提取 answer 字段作为分析内容
                  if (data.answer) {
                    // 清空之前的内容，显示完整的分析结果
                    aiAnalysisText.value = data.answer
                    displayedText.value = '' // 重置显示文本以触发打字机效果
                    clearTypingEffect() // 清除之前的打字机效果
                    startTypingEffect()
                  }
                  // 如果有 question，保存并显示
                  if (data.question) {
                    aiQuestion.value = data.question
                    console.log('   问题:', data.question)
                  }
                  // 标记为完成状态
                  aiStatus.value = 'completed'
                  break
                
                case 'stream':
                  // 流式文本：逐步追加
                  if (data.content || data.text) {
                    const text = data.content || data.text
                    aiAnalysisText.value += text
                    startTypingEffect()
                  }
                  break
                
                case 'error':
                  console.error('❌ [AI分析] 服务端错误:', data.message || data.error)
                  aiStatus.value = 'error'
                  aiErrorMessage.value = data.message || data.error || '服务端错误'
                  break
                
                case 'completed':
                case 'done':
                  console.log('✅ [AI分析] 分析完成')
                  aiStatus.value = 'completed'
                  break
                
                default:
                  // 未知类型：尝试提取通用字段
                  console.log('⚠️ [AI分析] 未知消息类型:', data.type)
                  if (data.content || data.text || data.message) {
                    const text = data.content || data.text || data.message
                    aiAnalysisText.value += text
                    startTypingEffect()
                  }
              }
            }
          },
          
          onError: (error) => {
            console.error('❌ [AI分析] 连接错误:', error)
            aiStatus.value = 'error'
            
            // 根据错误类型提供更具体的错误信息
            if (error.code === 'TIMEOUT') {
              aiErrorMessage.value = '连接超时：AI 分析服务暂时无法访问，请稍后重试'
            } else if (error.code === 'CONNECTION_FAILED') {
              aiErrorMessage.value = '连接失败：无法连接到 AI 分析服务，请检查网络或联系管理员'
            } else if (error.message) {
              aiErrorMessage.value = error.message
            } else {
              aiErrorMessage.value = '连接失败，无法获取 AI 分析结果'
            }
          },
          
          onClose: (event) => {
            console.log('🔌 [AI分析] 连接关闭')
            if (aiStatus.value !== 'error' && aiStatus.value !== 'completed') {
              aiStatus.value = 'disconnected'
            }
          }
        })
      } catch (error) {
        console.error('❌ [AI分析] 建立连接失败:', error)
        aiStatus.value = 'error'
        aiErrorMessage.value = '建立连接失败: ' + error.message
      }
    }

    // 打字机效果
    const startTypingEffect = () => {
      // 如果已经在打字，不重复启动
      if (isTyping.value) return
      
      isTyping.value = true
      
      const typeNextChar = () => {
        const fullText = aiAnalysisText.value
        const currentLength = displayedText.value.length
        
        if (currentLength < fullText.length) {
          // 还有字符未显示，继续打字
          displayedText.value = fullText.substring(0, currentLength + 1)
          typingInterval = setTimeout(typeNextChar, 30)
        } else {
          // 所有字符已显示完
          isTyping.value = false
          typingInterval = null
        }
      }
      
      // 开始打字
      typeNextChar()
    }
    
    // 清理打字机定时器
    const clearTypingEffect = () => {
      if (typingInterval) {
        clearTimeout(typingInterval)
        typingInterval = null
      }
      isTyping.value = false
    }

    // 获取 AI 状态文本
    const getAIStatusText = () => {
      const statusMap = {
        'idle': '待连接',
        'connecting': '连接中...',
        'connected': '分析中...',
        'completed': '分析完成',
        'error': '连接失败',
        'disconnected': '已断开'
      }
      return statusMap[aiStatus.value] || '未知状态'
    }

    // 重试 AI 连接
    const retryAIConnection = () => {
      if (!originalSessionId.value) {
        uni.showToast({
          title: '缺少会话ID，无法重试',
          icon: 'none'
        })
        return
      }
      
      // 关闭旧连接
      if (aiWebSocket.value) {
        closeLLMConnection(aiWebSocket.value)
        aiWebSocket.value = null
      }
      
      // 重新连接
      connectToAIAnalysis(originalSessionId.value)
    }

    // 组件卸载时清理
    onUnmounted(() => {
      if (aiWebSocket.value) {
        console.log('🧹 [AI分析] 组件卸载，关闭 WebSocket 连接')
        closeLLMConnection(aiWebSocket.value)
        aiWebSocket.value = null
      }
      clearTypingEffect()
    })

    const calculateTotalRainfall = (rainfallArray) => {
      if (!rainfallArray || rainfallArray.length === 0) return 0
      const total = rainfallArray.reduce((sum, item) => sum + (item.rain || 0), 0)
      return total.toFixed(2)
    }

    const getMethodLabel = (method) => {
      return method === 'average' ? '平均分配' : method === 'proportional' ? '等比例放大' : method
    }

    const resetForm = () => {
      results.value = null
      progressSteps.value.forEach(step => {
        step.active = false
        step.completed = false
      })
      
      // 重置 AI 分析状态
      showAIAnalysis.value = false
      aiStatus.value = 'idle'
      aiAnalysisText.value = ''
      aiQuestion.value = ''
      displayedText.value = ''
      aiErrorMessage.value = ''
      originalSessionId.value = null
      
      // 关闭 WebSocket 连接
      if (aiWebSocket.value) {
        closeLLMConnection(aiWebSocket.value)
        aiWebSocket.value = null
      }
      
      // 清理打字机效果
      clearTypingEffect()
    }

    const closeModal = () => {
      emit('close')
    }

    return {
      config,
      loading,
      loadingMessage,
      isProcessing,
      results,
      progressSteps,
      canSubmit,
      addRainfallValue,
      removeRainfallValue,
      applyPreset,
      submitHypothetical,
      calculateTotalRainfall,
      getMethodLabel,
      resetForm,
      closeModal,
      // AI 分析相关
      showAIAnalysis,
      aiStatus,
      aiAnalysisText,
      aiQuestion,
      displayedText,
      isTyping,
      aiErrorMessage,
      getAIStatusText,
      retryAIConnection
    }
  }
}
</script>

<style scoped>
.hypothetical-container {
  width: 100%;
  height: 100vh;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  overflow-y: auto;
  padding: 32rpx;
}

.header {
  text-align: center;
  margin-bottom: 48rpx;
  color: white;
}

.title {
  display: block;
  font-size: 40rpx;
  font-weight: 600;
  margin-bottom: 16rpx;
  color: white;
}

.subtitle {
  display: block;
  font-size: 26rpx;
  color: rgba(255, 255, 255, 0.9);
}

.config-panel {
  background: white;
  border-radius: 8rpx;
  padding: 40rpx;
  box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
  border: 1px solid #e8e8e8;
}

.config-section {
  margin-bottom: 60rpx;
}

.section-title {
  display: flex;
  align-items: center;
  font-size: 30rpx;
  font-weight: 600;
  margin-bottom: 32rpx;
  color: #262626;
}

.section-title .icon {
  margin-right: 16rpx;
}

.form-group {
  margin-bottom: 48rpx;
}

.label {
  display: block;
  font-size: 26rpx;
  font-weight: 600;
  color: #262626;
  margin-bottom: 20rpx;
}

.radio-group {
  display: flex;
  flex-direction: column;
  gap: 24rpx;
}

.radio-item {
  display: flex;
  align-items: flex-start;
  padding: 24rpx;
  background: #fafafa;
  border-radius: 6rpx;
  border: 2px solid #d9d9d9;
  cursor: pointer;
  transition: all 0.2s;
}

.radio-item.active {
  background: #e6f7ff;
  border-color: #1890ff;
}

.radio-icon {
  font-size: 32rpx;
  color: #1890ff;
  margin-right: 20rpx;
  line-height: 1;
}

.radio-content {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.radio-label {
  font-size: 30rpx;
  font-weight: 600;
  color: #333;
  margin-bottom: 8rpx;
}

.radio-desc {
  font-size: 24rpx;
  color: #888;
}

.rainfall-input-container {
  display: flex;
  flex-direction: column;
  gap: 20rpx;
}

.rainfall-value-item {
  display: flex;
  align-items: center;
  gap: 16rpx;
}

.rainfall-input {
  flex: 1;
  height: 80rpx;
  padding: 0 32rpx;
  background: #f8f9fa;
  border: 2rpx solid #e0e0e0;
  border-radius: 16rpx;
  font-size: 28rpx;
  transition: all 0.3s;
}

.rainfall-input:focus {
  border-color: #667eea;
  background: white;
}

.remove-btn {
  width: 60rpx;
  height: 60rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #ff4444;
  color: white;
  border-radius: 50%;
  font-size: 40rpx;
  cursor: pointer;
}

.add-btn {
  padding: 20rpx;
  background: #f0f2f5;
  color: #595959;
  border: 2px dashed #d9d9d9;
  border-radius: 6rpx;
  text-align: center;
  font-size: 26rpx;
  cursor: pointer;
  transition: all 0.2s;
}

.add-btn:hover {
  border-color: #1890ff;
  color: #1890ff;
}

.add-btn:active {
  background: #e6f7ff;
}

.preset-buttons {
  display: flex;
  gap: 20rpx;
  flex-wrap: wrap;
}

.preset-btn {
  flex: 1;
  min-width: 200rpx;
  padding: 24rpx;
  background: #f0f0f0;
  border-radius: 16rpx;
  text-align: center;
  font-size: 26rpx;
  cursor: pointer;
  transition: all 0.3s;
}

.preset-btn:active {
  background: #e0e0e0;
}

.action-buttons {
  display: flex;
  gap: 24rpx;
  margin-top: 60rpx;
}

.btn {
  flex: 1;
  height: 88rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 16rpx;
  font-size: 30rpx;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.3s;
}

.btn-primary {
  background: #1890ff;
  color: white;
}

.btn-primary:hover {
  background: #40a9ff;
}

.btn-primary.disabled {
  background: #d9d9d9;
  color: rgba(0, 0, 0, 0.25);
  cursor: not-allowed;
}

.btn-secondary {
  background: white;
  color: #595959;
  border: 1px solid #d9d9d9;
}

.btn-sm {
  height: 60rpx;
  padding: 0 32rpx;
  font-size: 24rpx;
}

.loading-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 600rpx;
  padding: 40rpx;
}

.loading-card {
  background: rgba(255, 255, 255, 0.15);
  backdrop-filter: blur(30rpx);
  border-radius: 24rpx;
  padding: 80rpx 60rpx;
  box-shadow: 0 8rpx 32rpx rgba(31, 38, 135, 0.37);
  border: 1px solid rgba(255, 255, 255, 0.18);
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
  max-width: 700rpx;
}

.spinner {
  width: 100rpx;
  height: 100rpx;
  border: 8rpx solid rgba(255, 255, 255, 0.3);
  border-top-color: white;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

.loading-text {
  margin-top: 40rpx;
  font-size: 32rpx;
  font-weight: 600;
  color: white;
  text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.2);
}

.progress-steps {
  margin-top: 60rpx;
  width: 100%;
}

.progress-step {
  display: flex;
  align-items: center;
  padding: 24rpx 32rpx;
  margin-bottom: 16rpx;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 16rpx;
  border: 1px solid rgba(255, 255, 255, 0.15);
  opacity: 0.4;
  transition: all 0.3s;
}

.progress-step.active {
  opacity: 1;
  background: rgba(255, 255, 255, 0.2);
  border-color: rgba(255, 255, 255, 0.4);
  box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
}

.progress-step.completed {
  opacity: 1;
  background: rgba(255, 255, 255, 0.15);
  border-color: rgba(255, 255, 255, 0.3);
}

.step-icon {
  width: 48rpx;
  height: 48rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-right: 24rpx;
  font-size: 32rpx;
  color: rgba(255, 255, 255, 0.6);
}

.progress-step.active .step-icon {
  color: white;
  animation: pulse 1.5s ease-in-out infinite;
}

.progress-step.completed .step-icon {
  color: #52c41a;
}

@keyframes pulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.2); }
}

.step-text {
  font-size: 28rpx;
  color: rgba(255, 255, 255, 0.7);
}

.progress-step.active .step-text {
  color: white;
  font-weight: 600;
}

.progress-step.completed .step-text {
  color: rgba(255, 255, 255, 0.9);
}

.results-container {
  background: white;
  border-radius: 8rpx;
  padding: 40rpx;
  box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
  border: 1px solid #e8e8e8;
}

/* ========== AI 分析卡片样式 ========== */
.ai-analysis-card {
  margin-bottom: 32rpx;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  border-radius: 16rpx;
  padding: 32rpx;
  box-shadow: 0 8rpx 24rpx rgba(102, 126, 234, 0.3);
  position: relative;
  overflow: hidden;
}

.ai-analysis-card::before {
  content: '';
  position: absolute;
  top: -50%;
  left: -50%;
  width: 200%;
  height: 200%;
  background: linear-gradient(
    45deg,
    transparent,
    rgba(255, 255, 255, 0.1),
    transparent
  );
  animation: shimmer-ai 3s infinite;
}

@keyframes shimmer-ai {
  0% {
    transform: translateX(-100%) translateY(-100%) rotate(45deg);
  }
  100% {
    transform: translateX(100%) translateY(100%) rotate(45deg);
  }
}

.ai-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 24rpx;
  position: relative;
  z-index: 1;
}

.ai-title-row {
  display: flex;
  align-items: center;
  gap: 16rpx;
}

.ai-icon {
  font-size: 36rpx;
  animation: float 3s ease-in-out infinite;
}

@keyframes float {
  0%, 100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-8rpx);
  }
}

.ai-title {
  font-size: 32rpx;
  font-weight: 700;
  color: white;
  letter-spacing: 1rpx;
  text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.2);
}

.ai-status-badge {
  display: flex;
  align-items: center;
  gap: 8rpx;
  padding: 6rpx 16rpx;
  border-radius: 20rpx;
  background: rgba(255, 255, 255, 0.2);
  backdrop-filter: blur(10rpx);
  border: 1px solid rgba(255, 255, 255, 0.3);
}

.status-dot {
  width: 12rpx;
  height: 12rpx;
  border-radius: 50%;
  background: #52c41a;
}

.ai-status-badge.connecting .status-dot {
  background: #faad14;
  animation: pulse-dot 1.5s infinite;
}

.ai-status-badge.connected .status-dot {
  background: #1890ff;
  animation: pulse-dot 1.5s infinite;
}

.ai-status-badge.completed .status-dot {
  background: #52c41a;
}

.ai-status-badge.error .status-dot {
  background: #ff4d4f;
}

.ai-status-badge.disconnected .status-dot {
  background: #8c8c8c;
}

@keyframes pulse-dot {
  0%, 100% {
    opacity: 1;
    transform: scale(1);
  }
  50% {
    opacity: 0.5;
    transform: scale(1.3);
  }
}

.status-text {
  font-size: 22rpx;
  color: white;
  font-weight: 600;
}

.ai-actions {
  display: flex;
  gap: 12rpx;
}

.retry-btn {
  padding: 8rpx 20rpx;
  background: rgba(255, 255, 255, 0.9);
  border-radius: 8rpx;
  font-size: 24rpx;
  color: #667eea;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.3s;
  border: 1px solid rgba(255, 255, 255, 0.5);
}

.retry-btn:hover {
  background: white;
  transform: translateY(-2rpx);
  box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.15);
}

.ai-content {
  background: rgba(255, 255, 255, 0.95);
  border-radius: 12rpx;
  padding: 28rpx;
  min-height: 200rpx;
  position: relative;
  z-index: 1;
  backdrop-filter: blur(10rpx);
  border: 1px solid rgba(255, 255, 255, 0.5);
}

/* Connecting State */
.ai-connecting {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 20rpx;
  padding: 40rpx;
}

.connecting-spinner {
  width: 60rpx;
  height: 60rpx;
  border: 4rpx solid #e6f7ff;
  border-top-color: #667eea;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

.connecting-text {
  font-size: 26rpx;
  color: #595959;
  font-weight: 500;
}

/* Analyzing State */
.ai-analyzing {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 20rpx;
  padding: 40rpx;
}

.analyzing-animation {
  display: flex;
  gap: 12rpx;
}

.analyzing-animation .dot {
  font-size: 32rpx;
  color: #667eea;
  animation: bounce 1.4s infinite ease-in-out;
}

.analyzing-animation .dot:nth-child(1) {
  animation-delay: -0.32s;
}

.analyzing-animation .dot:nth-child(2) {
  animation-delay: -0.16s;
}

@keyframes bounce {
  0%, 80%, 100% {
    transform: scale(0.8);
    opacity: 0.5;
  }
  40% {
    transform: scale(1.2);
    opacity: 1;
  }
}

.analyzing-text {
  font-size: 26rpx;
  color: #595959;
  font-weight: 500;
}

/* Text Display */
.ai-text-display {
  position: relative;
  line-height: 2;
  padding: 32rpx;
  background: rgba(255, 255, 255, 0.03);
  border-radius: 16rpx;
  border: 1px solid rgba(59, 130, 246, 0.15);
  margin-top: 24rpx;
}

/* Question Title */
.ai-question-title {
  display: flex;
  align-items: center;
  margin-bottom: 24rpx;
  padding-bottom: 24rpx;
  border-bottom: 1px solid rgba(59, 130, 246, 0.15);
}

.question-icon {
  font-size: 36rpx;
  margin-right: 12rpx;
}

.question-text {
  font-size: 30rpx;
  font-weight: 600;
  color: #3b82f6;
  line-height: 1.5;
  flex: 1;
}

/* Answer Content */
.ai-answer-content {
  position: relative;
}

.ai-text {
  font-size: 28rpx;
  color: #262626;
  white-space: pre-wrap;
  word-wrap: break-word;
  line-height: 1.8;
}

.typing-cursor {
  display: inline-block;
  width: 2rpx;
  height: 32rpx;
  background: #667eea;
  margin-left: 4rpx;
  animation: blink 1s infinite;
  vertical-align: middle;
}

@keyframes blink {
  0%, 100% {
    opacity: 1;
  }
  50% {
    opacity: 0;
  }
}

/* Error State */
.ai-error {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16rpx;
  padding: 40rpx;
  text-align: center;
}

.error-icon {
  font-size: 48rpx;
}

.error-text {
  font-size: 26rpx;
  color: #ff4d4f;
  font-weight: 500;
  margin-bottom: 16rpx;
}

.error-troubleshooting {
  width: 100%;
  margin-top: 20rpx;
  padding: 24rpx;
  background: #fff7e6;
  border-radius: 8rpx;
  border: 1px solid #ffd591;
  text-align: left;
}

.troubleshooting-title {
  display: block;
  font-size: 24rpx;
  font-weight: 600;
  color: #fa8c16;
  margin-bottom: 12rpx;
}

.troubleshooting-steps {
  display: flex;
  flex-direction: column;
  gap: 8rpx;
}

.troubleshooting-steps .step {
  font-size: 22rpx;
  color: #8c8c8c;
  line-height: 1.6;
}

/* Disconnected State */
.ai-disconnected {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16rpx;
  padding: 40rpx;
  text-align: center;
}

.disconnected-icon {
  font-size: 48rpx;
}

.disconnected-text {
  font-size: 26rpx;
  color: #8c8c8c;
  font-weight: 500;
}

.results-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 32rpx;
  padding-bottom: 24rpx;
  border-bottom: 2px solid #f0f2f5;
}

.results-title {
  font-size: 32rpx;
  font-weight: 600;
  color: #262626;
}

.forecast-card {
  margin-bottom: 32rpx;
  background: white;
  border-radius: 12rpx;
  padding: 32rpx;
  box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.12);
  border: 3px solid #e8e8e8;
}

.real-forecast {
  border-color: #52c41a;
  border-width: 4px;
}

.hypothetical-forecast {
  border-color: #1890ff;
  border-width: 4px;
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 24rpx;
  padding-bottom: 16rpx;
  border-bottom: 1px solid #f0f0f0;
}

.card-title {
  font-size: 30rpx;
  font-weight: 600;
  color: #262626;
}

.rainfall-badge {
  padding: 8rpx 20rpx;
  border-radius: 6rpx;
  font-size: 24rpx;
  font-weight: 600;
  line-height: 1.5;
}

.rainfall-badge.real {
  background: #52c41a;
  color: white;
}

.rainfall-badge.hypothetical {
  background: #1890ff;
  color: white;
}

.method-tag {
  display: inline-block;
  padding: 4rpx 12rpx;
  background: #fafafa;
  border-radius: 4rpx;
  font-size: 20rpx;
  color: #595959;
  margin-bottom: 16rpx;
  border: 1px solid #d9d9d9;
}

.card-content {
  margin-top: 24rpx;
}

.chart-section {
  margin-bottom: 24rpx;
  padding: 20rpx;
  background: white;
  border-radius: 8rpx;
  border: 2px solid #e8e8e8;
  box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
}

.no-chart-message {
  padding: 60rpx 40rpx;
  text-align: center;
  background: #fafafa;
  border-radius: 8rpx;
  border: 2px dashed #d9d9d9;
  margin-bottom: 24rpx;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12rpx;
}

.no-chart-message .icon {
  font-size: 48rpx;
  margin-bottom: 8rpx;
}

.no-chart-message .message-text {
  font-size: 26rpx;
  color: #262626;
  font-weight: 600;
}

.no-chart-message .message-detail {
  font-size: 22rpx;
  color: #8c8c8c;
}

.no-chart-message .session-info {
  font-size: 20rpx;
  color: #bfbfbf;
  font-family: Monaco, monospace;
  margin-top: 8rpx;
}

.hypothetical-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(600rpx, 1fr));
  gap: 24rpx;
}

.info-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 20rpx;
  margin-top: 24rpx;
  padding-top: 24rpx;
  border-top: 1px solid #f0f0f0;
}

.info-item {
  display: flex;
  flex-direction: column;
  padding: 16rpx;
  background: #f8f8f8;
  border-radius: 6rpx;
  border: 1px solid #e8e8e8;
}

.info-label {
  font-size: 20rpx;
  color: #8c8c8c;
  margin-bottom: 8rpx;
}

.info-value {
  font-size: 24rpx;
  font-weight: 600;
  color: #262626;
}
</style>


